home *** CD-ROM | disk | FTP | other *** search
- //: C12:RefcountTrace.cpp
- // From Thinking in C++, 2nd Edition
- // Available at http://www.BruceEckel.com
- // (c) Bruce Eckel 1999
- // Copyright notice in Copyright.txt
- // Refcount.cpp w/ trace info
- #include "../require.h"
- #include <cstring>
- #include <fstream>
- using namespace std;
-
- ofstream out("rctrace.out");
-
- class Counted {
- class MemBlock {
- static const int size = 100;
- char c[size];
- int refcount;
- static int blockcount;
- int blocknum;
- public:
- MemBlock() {
- memset(c, 1, size);
- refcount = 1;
- blocknum = blockcount++;
- }
- MemBlock(const MemBlock& rv) {
- memcpy(c, rv.c, size);
- refcount = 1;
- blocknum = blockcount++;
- print("copied block");
- out << endl;
- rv.print("from block");
- }
- ~MemBlock() {
- out << "\tdestroying block "
- << blocknum << endl;
- }
- void print(const char* msg = "") const {
- if(*msg) out << msg << ", ";
- out << "blocknum:" << blocknum;
- out << ", refcount:" << refcount;
- }
- void attach() { ++refcount; }
- void detach() {
- require(refcount != 0);
- // Destroy object if no one is using it:
- if(--refcount == 0) delete this;
- }
- int count() const { return refcount; }
- void set(char x) { memset(c, x, size); }
- // Conditionally copy this MemBlock.
- // Call before modifying the block; assign
- // resulting pointer to your block;
- MemBlock* unalias() {
- // Don't duplicate if not aliased:
- if(refcount == 1) return this;
- --refcount;
- // Use copy-constructor to duplicate:
- return new MemBlock(*this);
- }
- }* block;
- static const int sz = 30;
- char ident[sz];
- public:
- Counted(const char* id = "tmp") {
- block = new MemBlock; // Sneak preview
- strncpy(ident, id, sz);
- }
- Counted(const Counted& rv) {
- block = rv.block; // Pointer assignment
- block->attach();
- strncpy(ident, rv.ident, sz);
- strncat(ident, " copy", sz - strlen(ident));
- }
- void unalias() { block = block->unalias(); }
- void addname(const char* nm) {
- strncat(ident, nm, sz - strlen(ident));
- }
- Counted& operator=(const Counted& rv) {
- print("inside operator=\n\t");
- if(&rv == this) {
- out << "self-assignment" << endl;
- return *this;
- }
- // Clean up what you're using first:
- block->detach();
- block = rv.block; // Like copy-constructor
- block->attach();
- return *this;
- }
- // Decrement refcount, conditionally destroy
- ~Counted() {
- out << "preparing to destroy: " << ident
- << "\n\tdecrementing refcount ";
- block->print();
- out << endl;
- block->detach();
- }
- // Copy-on-write:
- void write(char value) {
- unalias();
- block->set(value);
- }
- void print(const char* msg = "") {
- if(*msg) out << msg << " ";
- out << "object " << ident << ": ";
- block->print();
- out << endl;
- }
- };
-
- int Counted::MemBlock::blockcount = 0;
-
- int main() {
- Counted A("A"), B("B");
- Counted C(A);
- C.addname(" (C) ");
- A.print();
- B.print();
- C.print();
- B = A;
- A.print("after assignment\n\t");
- B.print();
- out << "Assigning C = C" << endl;
- C = C;
- C.print("calling C.write('x')\n\t");
- C.write('x');
- out << "\n exiting main()" << endl;
- } ///:~
-